﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Irrlicht.Net.GUI;

namespace Irrlicht.Net
{              
    public enum EventTypes     
    {                              
        GUI = 0,
        MouseInput,
        KeyInput,                 
        JoystickInput,
        LogText,                 
        User,                 
        Force32Bit = 0x7fffffff         
    };

    public enum MouseInputEvents
    {                 
        LMousePressedDown = 0,                 
        RMousePressedDown,         
        MMousePressedDown,
        LMouseLeftUp,
        RMouseLeftUp,
        MMouseLeftUp,
        MouseMoved,
        MouseWheel,
        LMouseDoubleClick,
        RMouseDoubleClick,
        MMouseDoubleClick,
        LMouseTripleClick,
        RMouseTripleClick,
        MMouseTripleClick,
        Count         
    };

    public enum MouseButtonStateMasks         
    {     
        Left    = 0x01,
        Right   = 0x02,
        Middle  = 0x04,
        Extra1  = 0x08,
        Extra2  = 0x10,
        Force32Bit = 0x7fffffff        
    };

    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct IrrEventRaw
    {
        [FieldOffset(0)] 
        public EventTypes EventType;

        // GUIEvent
        [FieldOffset(4)]
        public IntPtr Caller;
        [FieldOffset(8)]
        public IntPtr Element;
        [FieldOffset(12)]
        public GUIEventTypes GUIEventType;

        // MouseInput
        [FieldOffset(4)]
        public int MouseX;
        [FieldOffset(8)]
        public int MouseY;
        [FieldOffset(12)]
        public double MouseWheel;
        [FieldOffset(16)]
        public uint MouseModifiers;
        [FieldOffset(20)]
        public uint MouseButtonStates;
        [FieldOffset(24)]
        public MouseInputEvents MouseEvent;

        // KeyInput
        [FieldOffset(4)]
        public char Char;
        [FieldOffset(8)]
        public KeyCodes Key;
        [FieldOffset(12)]
        public uint KeyModifiers;

        // JoystickEvent
        [FieldOffset(4)]
        public uint ButtonStates;
        [FieldOffset(8)]
        public short AxisX;
        [FieldOffset(10)]
        public short AxisY;
        [FieldOffset(12)]
        public short AxisZ;
        [FieldOffset(14)]
        public short AxisT;
        [FieldOffset(16)]
        public short AxisU;
        [FieldOffset(18)]
        public short AxisV;
        [FieldOffset(20)]
        public ushort POV;
        [FieldOffset(22)]
        public byte Joystick;

        // LogEvent
        [FieldOffset(4)]
        public IntPtr LogTextPtr;
        [FieldOffset(8)]
        public LogLevel LogLevel;

        // UserEvent
        [FieldOffset(4)]
        public int UserData1;
        [FieldOffset(8)]
        public int UserData2;
    };

    public class IrrEventArgs
    {
        public EventTypes EventType;
        public GUIEvent GUIEvent;
        public MouseInput MouseInput;
        public KeyInput KeyInput;
        public JoystickEvent JoystickEvent;
        public LogEvent LogEvent;
        public UserEvent UserEvent;
    }

    //[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct GUIEvent         
    {
        public Element Caller;
        public Element Element;
        public GUIEventTypes GUIEventType;
    };

    //[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct MouseInput
    {
        private enum MouseInputModifierMasks
        {
            ShiftMask   = 0x01,
            ControlMask = 0x02
        };

        public int X;
        public int Y;
        public double Wheel;
        public uint Modifiers;  // Need to emulate a bitfield here.
                         // bool Shift:1;
                         // bool Control:1;
        public uint ButtonStates;
        public MouseInputEvents Event;

        public bool isLeftPressed()
        { 
            return 0 != (this.ButtonStates & (uint) MouseButtonStateMasks.Left); 
        }

        public bool isRightPressed()
        {
            return 0 != (this.ButtonStates & (uint)MouseButtonStateMasks.Right);         
        }

        public bool isMiddlePressed()                        
        {
            return 0 != (this.ButtonStates & (uint)MouseButtonStateMasks.Middle); 
        }

        public bool Shift
        {
            get
            {
                return 0 != (this.Modifiers & (uint)MouseInputModifierMasks.ShiftMask);
            }
        }

        public bool Control
        {
            get
            {
                return 0 != (this.Modifiers & (uint)MouseInputModifierMasks.ControlMask);
            }
        }
    };

    //[StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct KeyInput
    {
        private enum KeyInputModifierMasks
        {
            PressedDownMask = 0x01,
            ShiftMask       = 0x02,
            ControlMask     = 0x04
        };

        //[FieldOffset(0)]
        public char Char;
        //[FieldOffset(4)]
        public KeyCodes Key;
        //[FieldOffset(8)]
        public uint KeyModifiers;
        // bool PressedDown:1;
        // bool Shift:1;        
        // bool Control:1;

        public bool PressedDown
        {
            get
            {
                return 0 != (this.KeyModifiers & (uint)KeyInputModifierMasks.PressedDownMask);
            }
        }

        public bool Shift
        {
            get
            {
                return 0 != (this.KeyModifiers & (uint)KeyInputModifierMasks.ShiftMask);
            }
        }

        public bool Control
        {
            get
            {
                return 0 != (this.KeyModifiers & (uint)KeyInputModifierMasks.ControlMask);
            }
        }
    };
 
    //[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct JoystickEvent         
    {
        public enum Buttons
        {
            Count = 32
        }

        public enum JoystickAxes             
        {                    
            AxisX = 0,     // e.g. analog stick 1 left to right
            AxisY,         // e.g. analog stick 1 top to bottom
            AxisZ,         // e.g. throttle, or analog 2 stick 2 left to right
            AxisR,         // e.g. rudder, or analog 2 stick 2 top to bottom
            AxisU,
            AxisV,
            Count
        };
                
        //[FieldOffset(0)] 
        public uint ButtonStates;
        //[FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
        public short[] Axis;
        //[FieldOffset(16)]
        public ushort POV;
        //[FieldOffset(18)]
        public byte Joystick;

        /*public uint ButtonStates;
        public short AxisX;
        public short AxisY;
        public short AxisZ;
        public short AxisT;
        public short AxisU;
        public short AxisV;
        public ushort POV;
        public byte Joystick;*/

        public bool IsButtonPressed(uint button)                
        {
            if(button >= (uint)Buttons.Count)  
            {
                return false;
            }

            return ((this.ButtonStates & (1 << (byte)button)) > 0) ? true : false;
        }
    };
    
    //[StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct LogEvent
    {
        public string Text;
        //[FieldOffset(0)]//, MarshalAs(UnmanagedType.LPStr)]
        //public IntPtr Text;
        //[FieldOffset(4)]
        public LogLevel Level;
    };
        
    //[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct UserEvent
    {
        public int UserData1;
        public int UserData2;
    };

    public interface IEventReceiver
    {
        bool OnEvent(IrrEventArgs e);
    }
}
